-
Notifications
You must be signed in to change notification settings - Fork 424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Malicious site protection navigation detection #3707
base: alessandro/malicious-site-protection
Are you sure you want to change the base?
Malicious site protection navigation detection #3707
Conversation
@@ -26,11 +27,14 @@ import Foundation | |||
/// advanced information related to the error. | |||
protocol SpecialErrorPageActionHandler { | |||
/// Handles the action of navigating to the site associated with the error page | |||
func visitSite() | |||
@MainActor | |||
func visitSite(url: URL, errorData: SpecialErrorData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I’m a bit on the fence with this.
The idea was to have a generic protocol that all the sub-special error handlers should conform to.
For MaliciousSiteProtectionNavigationHandler
I need to pass the URL and SpecialErrorData but I don’t need them for the SSL handler. So I feel I’m violating the Interface Segregation principle. what do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you perhaps create two funcs visitSite, one without params and one with params? Different handlers would be implementing only one function leaving other implementation empty? It's not ideal but the simplest
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, if we encounter more cases like this where we’re stretching these protocols, we might need to reconsider whether it’s appropriate to treat all special errors the same way. For example, SSL and malicious site errors already exhibit different behaviors. I’ll leave it up to you, but perhaps we should treat them differently (not under same logic) from the start. We can discuss further in 2025 :)
let response = MaliciousSiteDetectionNavigationResponse(navigationAction: navigationAction, errorData: errorData) | ||
return .navigationHandled(.mainFrame(response)) | ||
} else { | ||
// Extract the URL of the source frame (the iframe) that initiated the navigation action |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look more into iFrame logic when I integrate with BSK
|
||
@MainActor | ||
func handleMaliciousExemptions(for navigationType: WKNavigationType, url: URL) { | ||
// TODO: check storing redirects |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will address this TODO in upcoming PR
@@ -90,7 +94,7 @@ extension SSLErrorPageNavigationHandler: SpecialErrorPageActionHandler { | |||
Pixel.fire(pixel: .certificateWarningLeaveClicked) | |||
} | |||
|
|||
func visitSite() { | |||
func visitSite(url: URL, errorData: SpecialErrorData) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8f0b90f
to
b6dbf5c
Compare
This PR has been inactive for more than 7 days and will be automatically closed 7 days from now. |
ef5bd3f
to
e2f654c
Compare
b6dbf5c
to
5c07c05
Compare
case "http://privacy-test-pages.site/security/badware/phishing.html": | ||
return .phishing | ||
case "http://privacy-test-pages.site/security/badware/malware.html": |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should it be http vs https?
also, we should be keeping all urls inside AppURLs
@@ -26,11 +27,14 @@ import Foundation | |||
/// advanced information related to the error. | |||
protocol SpecialErrorPageActionHandler { | |||
/// Handles the action of navigating to the site associated with the error page | |||
func visitSite() | |||
@MainActor | |||
func visitSite(url: URL, errorData: SpecialErrorData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you perhaps create two funcs visitSite, one without params and one with params? Different handlers would be implementing only one function leaving other implementation empty? It's not ideal but the simplest
/// - Returns: A Boolean value that indicates whether the navigation action was handled. | ||
func handleSpecialErrorNavigation(navigationAction: WKNavigationAction, webView: WKWebView) async -> Bool | ||
@MainActor | ||
func handleDecidePolicyFor(navigationAction: WKNavigationAction, webView: WKWebView) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it should be
func handleDecidePolicy(for navigationAction: WKNavigationAction, webView: WKWebView)
/// - webView: The web view from which the navigation request began. | ||
/// - Returns: A Boolean value that indicates whether to cancel or allow the navigation. | ||
@MainActor | ||
func handleDecidePolicyfor(navigationResponse: WKNavigationResponse, webView: WKWebView) async -> Bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo, "for" is lowercased, but I'd refer to my previous comment ^
/// the navigation event. | ||
/// - webView: The web view from which the navigation request began. | ||
@MainActor | ||
func createMaliciousSiteDetectionTask(for navigationAction: WKNavigationAction, webView: WKWebView) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd go with makeMalicious*
return | ||
} | ||
|
||
let threatDetectionTask: Task<MaliciousSiteProtectionNavigationResult, Never> = Task.detached { [weak self] in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is the Task detached?
guard let url = navigationAction.request.url else { | ||
return | ||
} | ||
|
||
if let aboutBlankURL = URL(string: "about:blank"), url == aboutBlankURL { | ||
return | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we put it under one guard, like so
guard let url = navigationAction.request.url, url != URL(string: "about:blank") else { return }
@@ -26,11 +27,14 @@ import Foundation | |||
/// advanced information related to the error. | |||
protocol SpecialErrorPageActionHandler { | |||
/// Handles the action of navigating to the site associated with the error page | |||
func visitSite() | |||
@MainActor | |||
func visitSite(url: URL, errorData: SpecialErrorData) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
However, if we encounter more cases like this where we’re stretching these protocols, we might need to reconsider whether it’s appropriate to treat all special errors the same way. For example, SSL and malicious site errors already exhibit different behaviors. I’ll leave it up to you, but perhaps we should treat them differently (not under same logic) from the start. We can discuss further in 2025 :)
self.startDownload(with: navigationResponse, decisionHandler: decisionHandler) | ||
} cancelHandler: { | ||
// If the navigation has been handled by the special error page handler cancel navigating to new content as the special error page will be shown. | ||
Task { @MainActor in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa :), this is triggering an alert for me. Making a task on this code could have bigger consequences – we’re essentially returning immediately and skipping the run loop, without a guarantee that other tasks spawned elsewhere won’t interfere with this. Are we sure this is the approach we want to take?
This PR has been inactive for more than 7 days and will be automatically closed 7 days from now. |
Task/Issue URL: https://app.asana.com/0/1206329551987282/1207151848931030
Tech Design URL: https://app.asana.com/0/1206329551987282/1207273224076495/f
Cc: @not-a-rootkit
Description:
This PR adds the navigation logic for detecting a malicious site and navigating to a special error page if the site is malicious.
The original idea in the tech design was to intercept the Request in
decidePolicyForNavigationAction
and check whether a site is malicious cancelling the request accordingly.We noticed that the above approach increases the page load time of websites due to the logic check.
I opted for an approach where in
decidePolicyForNavigationAction
we start the detection task in parallel without waiting and indecidePolicyForNavigationResponse
we evaluate the task’s result.Another approach I thought of was to perform the logic in the background in
didStartProvisionalNavigation
. The problem with this approach is that is called only for navigation that starts from the main frame so it would not be possible to intercept malicious iFrame URLs.NOTE
BSK Threat detection is currently mocked. Its integration and tests will follow in an upcoming PR.
Steps to test this PR:
Scenario 1 - Phishing Website should show special error page
Scenario 2 - Malware Website should show special error page
Scenario 3 - Allow visit a malicious website should not show the error again if navigating back to the site
Scenario 4 - Leave a malicious site should close the Tab
Definition of Done (Internal Only):
Copy Testing:
’
rather than'
Orientation Testing:
Device Testing:
OS Testing:
Theme Testing:
Internal references:
Software Engineering Expectations
Technical Design Template